#ifndef __MYSQLDBCONNPOLL_H__
#define __MYSQLDBCONNPOLL_H__ 

#include <iostream>
#include <unordered_map>
#include <chrono>
#include "logger.h"
#include "qsingleton.h"
#include "common.h"

#include <mysql.h>

#define MAX_DBUSER_SIZE 36
#define MAX_DBPASS_SIZE 36
#define MAX_DBIP_SIZE 36
#define MAX_DBNAME_SIZE 36

class UrlInfo
{
public:
  UrlInfo()
  {}

  UrlInfo(unsigned int hashcode, const char* url, bool autocommit = true)
    :hashcode_(hashcode)
    ,url_(url)
    ,autocommit_(autocommit)
  {
    parseUrl();
  }

  void parseUrl()
  {
    //mysql://user:passwd@ip:port/dbname
    LOG_INFO("FFL[%s, %s, %d], %s", LOG_FFL, url_.c_str());
    char buf[256] = {0};
    strcpy(buf, url_.c_str());

    unsigned int len = strlen("mysql:://");
    char* sub_str = &buf[len - 1];
    //LOG_INFO("FFL[%s, %s, %d], %s", LOG_FFL, sub_str);
    unsigned int i = 1;
    char* p = strtok(sub_str, ":@/");
    while(p)
    {
      switch(i)
      {
        case 1:
          {
            strcpy(user_, p); 
          }
          break;
        case 2:
          {
            strcpy(pass_, p);
          }
          break;
        case 3:
          {
            strcpy(ip_, p);
          }
          break;
        case 4:
          {
            port_ = atoi(p);
          }
          break;
        case 5:
          {
            strcpy(db_name_, p);
          }
          break;
      }
      p = strtok(NULL, ":@/");
      i++;
    }
    LOG_INFO("FFL[%s, %s, %d] user:%s, pass:%s, ip:%s, p:%u, dbname:%s",LOG_FFL, user_, pass_, ip_, port_, db_name_);
    
  }

  //数据库的hashcode
  unsigned int hashcode_;
  //数据库url
  const std::string url_;
  //db用户名
  char user_[MAX_DBUSER_SIZE];
  //密码
  char pass_[MAX_DBPASS_SIZE];
  //IP
  char ip_[MAX_DBIP_SIZE];
  //端口 默认3306
  unsigned int port_;
  //数据库名
  char db_name_[MAX_DBNAME_SIZE];
  //是否支持回滚
  bool autocommit_;

};

enum MysqlCon_Stae
{
  MysqlCon_Stae_Invalid,//不可用
  MysqlCon_Stae_Valid,//可用
  MysqlCon_Stae_Used,//被使用
};

typedef unsigned int Connid;

struct db_col
{
  const char* name_;//数据库字段名称
  unsigned int type_;//数据库字段类型
  unsigned int size_;//数据库字段大小
};

enum 
{
  DB_UINT8,  
  DB_CHAR,
  DB_UINT16,
  DB_UINT32,
  DB_UINT64,
  DB_FLOAT,
  DB_STR,
  DB_BIN,
};

typedef unsigned int (*hashCodeFunc)(const void* hashData);
class MysqlConn 
{
  public:
    MysqlConn(const UrlInfo& url);
    ~MysqlConn();

    bool initConn();
    bool setConnUsed();
    bool releaseConn();
    bool setTransaction(bool autocommit); 
    Connid getID()
    {
      return id_;
    }
    unsigned int getState()
    {
      return state_;
    }
     std::chrono::system_clock::time_point getUseTime()
     {
       return usetime_;
     }

    int exeSql(const char* sql);
    int exeCreate(const char* sql);
    //注意colum为db_col数组，并且需要NULL结尾
    int exeInsert(const char* tablename, const db_col* colum, const unsigned char* data);
    unsigned int fetchSelectSql(const char* tablename, const db_col* colum, const char* where, const char* order, const char* limit);
    unsigned int fullSelectDataByRow(MYSQL_ROW row, unsigned long* lengths, const db_col* colum, unsigned char* data);
    int exeSelect(const char* tablename, const db_col* colum, const char* where, const char* order, const char* limit,  unsigned char** data);
    int exeUpdate(const char* tablename, const db_col* colum, const unsigned char* data, const char* where);
    int exeDelete(const char* tablename, const char* where);





  private:
    Connid id_;
    static Connid id_generator_;

    MYSQL* conn_;


    const UrlInfo url_;
  
    unsigned int state_;//当前连接状态

    std::chrono::system_clock::time_point alivetime_;//存活时间
    std::chrono::system_clock::time_point usetime_;//连接时间

};


//连接池
typedef std::unordered_multimap<unsigned int, MysqlConn*> conn_pool_;//urlhashcode-mysqlconn 
//URL池
typedef std::unordered_map<unsigned int, UrlInfo*> url_pool_;//urlhashcode-urlinfo 
//所有mysql连接类
typedef std::unordered_map<Connid, MysqlConn*> conn_map_;//mysqlconnid-mysqlconn

class MysqlConnPool : public qSingleton<MysqlConnPool>
{
  friend class qSingleton<MysqlConnPool>;
private:
  MysqlConnPool(const MysqlConnPool&);
  MysqlConnPool& operator=(const MysqlConnPool&);

  MysqlConnPool(hashCodeFunc hashFunc = nullptr);
  ~MysqlConnPool();
public:
  bool init(const char* urlsql);
  bool putUrl(unsigned int hashcode, const char* url);

  MysqlConn* getHandleByHashCode(unsigned int hashcode);

  Connid getHandle(const void* hashData)
  {
    unsigned int hashcode = 0;
    if(hashData)
    {
      hashcode = hashFunc_(hashData);
    }

    MysqlConn* conn = getHandleByHashCode(hashcode);
    if(!conn)
      return -1;

    return conn->getID();
  }

  MysqlConn* getHandleByID(Connid id)
  {
    conn_map_::iterator it = connmap_.find(id);
    if(it != connmap_.end())
    {
      return it->second;
    }
    return nullptr;
  }
  void setMaxNum(uint32 num)
  {
    maxnum_ = num;
  }
  void setTimeOut(uint32 timeout)
  {
    limit_timout_ = timeout;
  }

  int exeCreate(Connid id, const char* sql);
  int exeSelect(Connid id, const char* tablename, const db_col* colum, const char* where, const char* order, const char* limit, unsigned char** data);
  int exeInsert(Connid id, const char* tablename, const db_col* colum, const unsigned char* data);
  int exeUpdate(Connid id, const char* tablename, const db_col* colum, const unsigned char* data, const char* where);
  int exeDelete(Connid id, const char* tablename, const char* where);

private:
  conn_pool_ conns_;
  url_pool_ urls_;
  conn_map_ connmap_;
  hashCodeFunc hashFunc_;

  uint32 maxnum_;
  uint32 limit_timout_;
};

#endif
